package com.docking.heylo.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.response.AlipayTradeAppPayResponse;
import com.docking.heylo.ThreadContext;
import com.docking.heylo.constant.SystemConstant;
import com.docking.heylo.dao.entity.*;
import com.docking.heylo.dao.mapper.*;
import com.docking.heylo.enums.*;
import com.docking.heylo.exception.GeneralException;
import com.docking.heylo.pojo.PayOrderPackage;
import com.docking.heylo.service.*;
import com.docking.heylo.utils.HeyloMessageSource;
import com.docking.heylo.web.dto.AppointmentDto;
import com.docking.heylo.web.dto.OrderPayDto;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;

@Service
public class AppointmentServiceImpl implements IAppointmentService {

    @Resource
    private AppointmentMapper appointmentMapper;

    @Resource
    private DictMapper dictMapper;

    @Resource
    private PayOrderMapper orderMapper;

    @Autowired
    private ICouponService couponService;

    @Autowired
    private IAccountService accountService;

    @Autowired
    private AliPayServerImpl aliPayServer;

    @Autowired
    private WeChatPayServerImpl weChatPayServer;

    @Resource
    private UserMapper userMapper;

    @Autowired
    private HeyloMessageSource messageSource;

    @Autowired
    private IMessageService messageService;

    @Autowired
    private IBuddyService buddyService;


    private BigDecimal b100 = BigDecimal.valueOf(100);

    @Value("${notify.wechat}")
    private String wechatNotifyUrl;

    @Value("${notify.aliPay}")
    private String alipayNotifyUrl;

    @Override
    public List<Map<String, Object>> costConf() {
        return dictMapper.selectConfByParentName("appointment_conf");
    }

    public Map<String, Object> mapCostConf(){
        Map<String, Object> costConf = new HashMap<>();
        for(Map<String, Object> map : costConf()){
            costConf.put(map.get("name").toString(), map.get("value"));
        }
        return costConf;
    }


    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public void initiate(Appointment appointment) {
        // 当前用户角色为摄影师，无法发起约拍
        if(ThreadContext.type().intValue() == EProfession.photographer.getValue()){
            throw new GeneralException(messageSource.getMessage("not.appointment"));
        }

        // 邀约对象为摄影师，无法发起约拍
        User user = userMapper.selectByPrimaryKey(appointment.getPhotographerId());
        if(user.getType().intValue() != EProfession.photographer.getValue()){
            throw new GeneralException(messageSource.getMessage("not.appointment"));
        }

        // 如果是选择互免费，则需要判断双方是否是好友
        if(appointment.getGratis() == 1 && buddyService.friend(ThreadContext.userId(), appointment.getPhotographerId()) == null){
            throw new GeneralException(messageSource.getMessage("free.for.friends"));
        }

        appointment.setTipFee(appointment.getTipFee() == null ? BigDecimal.ZERO : appointment.getTipFee());

        // 计算约拍价格
        if(appointment.getGratis() == 1){       // 免费
            appointment.setFinalPrice(BigDecimal.ZERO);
            appointment.setDiscount(BigDecimal.ZERO);
            appointment.setStartingPrice(BigDecimal.ZERO);
        }else{                                  // 收费
            Map<String, Object> costConf = mapCostConf();
            BigDecimal platformDiscount = new BigDecimal(costConf.get("platform_discount").toString());     // 平台折扣
            BigDecimal startingPrice    = new BigDecimal(costConf.get("starting_price").toString());        // 起步价

            // 订单金额
            BigDecimal cost = BigDecimal.valueOf(appointment.getPictureCount()).abs().
                    multiply(new BigDecimal(costConf.get("refined_price").toString()))
                    .add(startingPrice)                 // 起步价
                    .subtract(platformDiscount)
                    .add(appointment.getTipFee().abs())
                    .setScale(2, BigDecimal.ROUND_DOWN)
                    ;
            appointment.setFinalPrice(cost);
            appointment.setDiscount(platformDiscount);
            appointment.setStartingPrice(startingPrice);

            // 优惠码
            if(!StringUtils.isEmpty(appointment.getPromoCode())){
                couponService.use(ThreadContext.userId(), appointment.getPromoCode());
                Coupon coupon = couponService.selectByPromoCode(appointment.getPromoCode());
                appointment.setFinalPrice(appointment.getFinalPrice().subtract(coupon.getValue()));
            }
        }

        appointment.setUserId(ThreadContext.userId());
        appointment.setStatus(EAppointmentState.create.getValue());
        appointment.setmScore(0);
        appointment.setpScore(0);
        appointment.setmEva((byte) 0);
        appointment.setpEva((byte) 0);
        appointment.setCrtAt(new Date());
        appointmentMapper.insertSelective(appointment);

        // 发送通知到摄影师
        messageService.sendMessage(appointment.getPhotographerId(),"您收到了一条约拍订单",new HashMap<String, String>(){{
            put("type", EMessageType.appointment.getValue() + "");

            put("body", JSONObject.toJSONString(new HashMap<String, String>(){{
                put("id", appointment.getId().toString());
                put("status", EAppointmentState.create.getValue() + "");
            }}));
        }});

    }

    @Override
    public PageInfo<Map<String, Object>> orders(AppointmentDto appointmentDto) {
        PageHelper.startPage(appointmentDto.getPageNumber(), appointmentDto.getSize());
        PageHelper.orderBy("crt_at desc");

        return new PageInfo<>(appointmentMapper.ordersForUser(appointmentDto.getStatus(), ThreadContext.userId(),
                ThreadContext.type()
        ));
    }

    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public void start(AppointmentDto appointmentDto) {
        Appointment appointment = appointmentMapper.selectByPrimaryKey(appointmentDto.getId());
        if(appointment.getPhotographerId() != ThreadContext.userId()){
            return;
        }

        if(appointment.getStatus().intValue() != EAppointmentState.paid.getValue()){
            throw new GeneralException(messageSource.getMessage("order.not_pay"));
        }

        appointmentMapper.updateByPrimaryKeySelective(new Appointment(){{
            setId(appointment.getId());
            setStatus(EAppointmentState.p_start.getValue());
            setStartingTime(new Date());
        }});
    }

    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public Object payAppointment(OrderPayDto orderPayDto) {
        Appointment appointment = appointmentMapper.selectByPrimaryKey(orderPayDto.getAppointmentId());
        if(appointment == null){
            throw new GeneralException("订单不存在");
        }

        if(appointment.getStatus().intValue() == EAppointmentState.paid.getValue()){
            throw new GeneralException("订单已支付");
        }

        // 创建支付订单
        PayOrder order = new PayOrder();
        order.setUserId(ThreadContext.userId());
        order.setAppointmentId(appointment.getId());
        order.setCrtAt(new Date());
        order.setStatus(EOrderState.create.getValue());
        order.setOrderNo(formatOrderNo());
        order.setDescription("支付订单约拍订单");
        order.setPayMethod(orderPayDto.getPayMethod());
        order.setAmount(appointment.getFinalPrice());
        orderMapper.insertSelective(order);

        // 创建支付记录
        accountService.payOut(order.getUserId(), order.getAmount(), order.getDescription(),
                appointment.getId(), order.getOrderNo(),EAccountRecord.BusinessYype.appointment_order,
                EPayMethod.getByValue(order.getPayMethod()), EOrderState.create
                );

        PayOrderPackage payOrder = new PayOrderPackage();
        payOrder.setAmount(order.getAmount());
        payOrder.setTradeNo(order.getOrderNo());
        payOrder.setBody(String.format("支付订单：%s",appointment.getClaim()));
        payOrder.setSubject(SystemConstant.subject);
        payOrder.setSpbillCreateIp(ThreadContext.ip());

        try{
            switch (orderPayDto.getPayMethod()){
                case 1:
                    payOrder.setNotifyUrl(alipayNotifyUrl);
                    AlipayTradeAppPayResponse response = aliPayServer.sendPay(payOrder);
                    return response;
                case 2:
                    return weChatPayServer.uniformorder(payOrder);
                default:
                    throw new GeneralException("不支持的支付方式");
            }
        }catch (AlipayApiException ex){
            throw new GeneralException("创建支付失败");
        }
    }

    public String formatOrderNo(){
        SimpleDateFormat sdf = new SimpleDateFormat("yyMMddsss");
        String no = (Math.random() + "").substring(3,8);
        return sdf.format(new Date()) + no;
    }

    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public void paymentCallback(String orderNo, EPayMethod payMethod, boolean bool) {
        PayOrder payOrder = payOrderByOrderNo(orderNo);
        if(payOrder == null || payOrder.getStatus().intValue() != EOrderState.create.getValue()){
            return;
        }

        // 更新支付订单记录
        orderMapper.updateByPrimaryKeySelective(new PayOrder(){{
            setId(payOrder.getId());
            setStatus(bool ? EOrderState.pay_success.getValue() : EOrderState.pay_error.getValue());
        }});

        if(bool){
            // 更新约拍订单状态
            appointmentMapper.updateByPrimaryKeySelective(new Appointment(){{
                setId(payOrder.getAppointmentId());
                setStatus(EAppointmentState.paid.getValue());
                setPaymentTime(new Date());
            }});

            // 更新账户记录状态
            accountService.updateStatus(payOrder.getUserId(), payOrder.getOrderNo(), EOrderState.pay_success);
        }
    }

    public PayOrder payOrderByOrderNo(String orderNo){
        PayOrderExample example = new PayOrderExample();
        PayOrderExample.Criteria criteria = example.createCriteria();
        criteria.andOrderNoEqualTo(orderNo);
        List<PayOrder> orders = orderMapper.selectByExample(example);
        return orders.size() > 0 ? orders.get(0) : null;
    }

    @Override
    public Coupon couponByCode(String promoCode) {
        return couponService.selectByPromoCode(promoCode);
    }

    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public void end(Appointment app) {
        Appointment appointment = appointmentMapper.selectByPrimaryKeyForUpdate(app.getId());

        if(appointment.getGratis() == 0){
           // 计算平台抽成
           Dict dict = dictMapper.selectByPrimaryKey(7);
           BigDecimal decimal = new BigDecimal(dict.getValue());

           BigDecimal fee = appointment.getFinalPrice().subtract(
                   appointment.getFinalPrice().multiply(decimal.divide(b100,2,BigDecimal.ROUND_DOWN))
           );

           accountService.credit(appointment.getPhotographerId(), fee, "约拍订单收入", appointment.getId(), null,
                   EAccountRecord.BusinessYype.appointment_order, EPayMethod.other, EOrderState.pay_success);
        }

        //  更新用户约拍次数
        userMapper.appointment(appointment.getUserId());

        // 更新摄影师约拍次数
        userMapper.appointment(appointment.getPhotographerId());
    }

    @Override
    public void endAppointment(Appointment app) {
        Appointment appointment = appointmentMapper.selectByPrimaryKeyForUpdate(app.getId());
        if (appointment.getStatus().equals(EAppointmentState.end.getValue())){
            throw new GeneralException(messageSource.getMessage("appointment.end"));
        }

        AppointmentExample example = new AppointmentExample();
        AppointmentExample.Criteria criteria = example.createCriteria();
        criteria.andStatusNotEqualTo(EAppointmentState.end.getValue());
        criteria.andIdEqualTo(appointment.getId());
        int row = appointmentMapper.updateByExampleSelective(new Appointment(){{
            setPhotographerEndTime(new Date());
            setStatus(EAppointmentState.end.getValue());
        }}, example);

        if(row != 1){
            throw new GeneralException(messageSource.getMessage("appointment.end"));
        }
    }


    @Override
    public void accept(AppointmentDto dto) {
        Appointment appointment = appointmentMapper.selectByPrimaryKey(dto.getId());
        if(appointment.getStatus().intValue() != EAppointmentState.create.getValue()){
           throw new GeneralException("请勿重复提交");
        }

        appointmentMapper.updateByPrimaryKeySelective(new Appointment(){{
            setId(dto.getId());
            setStatus(EAppointmentState.accept.getValue());
        }});

        // 不需要支付
        if(appointment.getGratis() == 1 && appointment.getFinalPrice().compareTo(BigDecimal.ZERO) == 0){
            appointmentMapper.updateByPrimaryKeySelective(new Appointment(){{
                setId(dto.getId());
                setStatus(EAppointmentState.paid.getValue());
            }});
        }

        // 发送通知
        messageService.sendMessage(appointment.getUserId(), "摄影师已经接收您的约拍请求", new HashMap<String, String>(){{
            put("type", EMessageType.appointment.getValue() + "");

            put("body", JSONObject.toJSONString(new HashMap<String, String>(){{
                put("id", appointment.getId().toString());
                put("status", EAppointmentState.accept.getValue() + "");
            }}));
        }});
    }

    @Override
    public void refuse(AppointmentDto dto) {
        Appointment appointment = appointmentMapper.selectByPrimaryKey(dto.getId());
        if(appointment.getStatus().intValue() != EAppointmentState.create.getValue()){
            throw new GeneralException("请勿重复提交");
        }

        appointmentMapper.updateByPrimaryKeySelective(new Appointment(){{
            setId(dto.getId());
            setStatus(EAppointmentState.refuse.getValue());
        }});

        // 发送通知
        messageService.sendMessage(appointment.getUserId(), "摄影师拒绝了您的约拍请求", new HashMap<String, String>(){{
            put("type", EMessageType.appointment.getValue() + "");

            put("body", JSONObject.toJSONString(new HashMap<String, String>(){{
                put("id", appointment.getId().toString());
                put("status", EAppointmentState.refuse.getValue() + "");
            }}));
        }});
    }


    @Override
    public void testPayOrder(AppointmentDto appointmentDto) {
        PayOrderExample example = new PayOrderExample();
        PayOrderExample.Criteria criteria = example.createCriteria();
        criteria.andAppointmentIdEqualTo(appointmentDto.getId());

        PayOrder order = orderMapper.selectByExample(example).get(0);

        paymentCallback(order.getOrderNo(), EPayMethod.test, true);
    }

    @Override
    public List<Appointment> selectNotConfirmationList() {
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.DAY_OF_MONTH, -14);

        Date endTime = calendar.getTime();
        calendar.add(Calendar.MINUTE, -1);

        Date beginTime = calendar.getTime();
        return appointmentMapper.selectNotConfirmationList(beginTime, endTime);
    }

    @Override
    public void automaticConfirmation() {
        List<Appointment> appointments = selectNotConfirmationList();
        for(Appointment appointment : appointments){
            // 订单状态异常不用处理
            try{
                end(appointment);

                // 发送通知
                messageService.sendMessage(appointment.getUserId(), "您的约拍订单已经自定确认!", new HashMap<String, String>(){{
                    put("type", EMessageType.appointment.getValue() + "");

                    put("body", JSONObject.toJSONString(new HashMap<String, String>(){{
                        put("id", appointment.getId().toString());
                        put("status", EAppointmentState.end.getValue() + "");
                    }}));
                }});
            }catch (GeneralException e){
            }
        }
    }

    @Override
    public void appeal(Appointment appointment) {
        Appointment dbAppointment = appointmentMapper.selectByPrimaryKey(appointment.getId());
        if(dbAppointment.getAppeal().intValue() != EAppointmentAppeal.no_appeal.getValue()){
            throw new GeneralException("订单已申诉");
        }
        appointmentMapper.updateByPrimaryKeySelective(new Appointment(){{
            setId(appointment.getId());
            setAppeal(EAppointmentAppeal.appealing.getValue());
            setAppealDesc(appointment.getAppealDesc());
        }});
    }






}
